﻿using System;
using System.Collections.Generic;

using System.Text;
using System.Net;
using System.Web;
using System.IO;
using OAuth;
using System.Diagnostics;
using System.Xml;

namespace SinaWeiBoWrapper
{
    class SinaWeiBoLogin
    {
        public enum Method { GET, POST };
        private string m_strAccessToken = null;
        public string AccessToken
        {
            get { return m_strAccessToken; }
            set { m_strAccessToken = value; }
        }
        private string m_strAccessTokenSecret = null;
        public string AccessTokenSecret
        {
            get { return m_strAccessTokenSecret; }
            set { m_strAccessTokenSecret = value; }
        }
        private string m_strConsumerKey = null;
        OAuthBase m_oOAuth = new OAuthBase();

        public string ConsumerKey
        {
            get { return m_strConsumerKey; }
            set { m_strConsumerKey = value; }
        }
        
        private string m_strConsumerSecret = "";

        public string ConsumerSecret
        {
            get { return m_strConsumerSecret; }
            set { m_strConsumerSecret = value; }
        }
        
 
        
        private string m_strVerifier = null;
        public string Verifier
        {
            get { return m_strVerifier; }
            set { m_strVerifier = value; }
        }


        private string m_strRequestTokenUrl = null;
        public string RequestTokenUrl
        {
            get { return m_strRequestTokenUrl; }
            set { m_strRequestTokenUrl = value; }
        }


        private string m_strAuthorizeUrl = null;
        public string AuthorizeUrl
        {
            get { return m_strAuthorizeUrl; }
            set { m_strAuthorizeUrl = value; }
        }

        private string m_strAccessTokenUrl = null;
        public string AccessTokenUrl
        {
            get { return m_strAccessTokenUrl; }
            set { m_strAccessTokenUrl = value; }
        }

        private Boolean m_bShowDebugInfo = false;
        public System.Boolean ShowDebugInfo
        {
            get { return m_bShowDebugInfo; }
            set { m_bShowDebugInfo = value; }
        }

        private string m_strOAuthToken = null;
        public string OAuthToken
        {
            get { return m_strOAuthToken; }
            set { m_strOAuthToken = value; }
        }
      
        private string m_strOAuthTokenSecret = null;
        public string OAuthTokenSecret
        {
            get { return m_strOAuthTokenSecret; }
            set { m_strOAuthTokenSecret = value; }
        }
        private string m_strloginedRequestString = null;
        public string StrloginedRequestString
        {
            get { return m_strloginedRequestString; }
        }
        public Boolean login(string astrUserName,string astrPassword)
        {
            //1.get RequestToken
            if (this.getRequestToken(ref this.m_strOAuthToken,ref this.m_strOAuthTokenSecret))
            {
                //2.getAuthorize
                if (this.getAuthorize(astrUserName,astrPassword,ref this.m_strVerifier))
                {
                    //3.getAccessToken
                    return this.getAccessToken(this.Verifier);
                }
            }

            return false;
            
        }

        private string getWebResponse(string astrUrl,string astrMethod,string astrPostData)
        {
            try
            {
                HttpWebRequest loRequest = (HttpWebRequest)WebRequest.Create(astrUrl.ToString());
               
                if (!string.IsNullOrEmpty(astrMethod) && astrMethod.ToUpper().CompareTo("POST") == 0 && !string.IsNullOrEmpty(astrPostData))
                {
                    loRequest.Method = "POST";
                    byte[] lpbyteArray = System.Text.Encoding.UTF8.GetBytes(astrPostData);
                    loRequest.ContentType = "application/x-www-form-urlencoded";
                    loRequest.ContentLength = lpbyteArray.Length;
                    Stream loDataStream = loRequest.GetRequestStream();
                    loDataStream.Write(lpbyteArray, 0, lpbyteArray.Length);
                    loDataStream.Close();

                }
                HttpWebResponse loResponse = (HttpWebResponse)loRequest.GetResponse();
                StreamReader loStream = new StreamReader(loResponse.GetResponseStream(), System.Text.Encoding.UTF8);
                string loResponseBody = loStream.ReadToEnd();
                loStream.Close();
                loResponse.Close();
                return loResponseBody;
            }
            catch (System.Exception ex)
            {
                if (this.m_bShowDebugInfo)
                {
                    Debug.WriteLine(ex.ToString());
                }
                return null;
            }

        }



        public string SendLoginedRequest(Method method, string url, string postData)
        {
            string outUrl = "";
            string querystring = "";
            string ret = "";
            string lstrTest = this.m_oOAuth.UrlEncode("http://www.sina.com.cn");
            
            //Setup postData for signing.
            //Add the postData to the querystring.
            if (method == Method.POST)
            {
                if (string.IsNullOrEmpty(postData))
                {
                    postData += "source=" + this.m_strConsumerKey;
                }else
                {
                    postData += "&source=" + this.m_strConsumerKey;
                }
                if (postData.Length > 0)
                {
                    //Decode the parameters and re-encode using the oAuth UrlEncode method.
                    System.Collections.Specialized.NameValueCollection qs = HttpUtility.ParseQueryString(postData);
                    postData = "";
                    foreach (string key in qs.AllKeys)
                    {
                        if (postData.Length > 0)
                        {
                            postData += "&";
                        }
                        qs[key] = (qs[key]);
                        postData += key + "=" + qs[key];

                    }
                    if (url.IndexOf("?") > 0)
                    {
                        url += "&";
                    }
                    else
                    {
                        url += "?";
                    }
                    url += postData;
                }
              
            }
            else if (method == Method.GET && !String.IsNullOrEmpty(postData))
            {
                url += "?source=" + this.m_strConsumerKey + "&" + postData;


            }

            Uri uri = new Uri(url);

            string nonce = this.m_oOAuth.GenerateNonce();
            string timeStamp = this.m_oOAuth.GenerateTimeStamp();
            string sig = m_oOAuth.GenerateSignature(uri,
                this.m_strConsumerKey,
                this.m_strConsumerSecret,
                this.m_strAccessToken,
                this.m_strAccessTokenSecret,
                method.ToString(),
                timeStamp,
                nonce,
                this.Verifier,
                out outUrl,
                out querystring);

            querystring += "&oauth_signature=" + HttpUtility.UrlEncode(sig);


            if (method == Method.POST)
            {
                postData = querystring;
                querystring = "";
            }

            if (querystring.Length > 0)
            {
                outUrl += "?" + querystring;
            }

            string lstrResponse = null;

            if (method == Method.POST)
            {
                lstrResponse = this.getWebResponse(outUrl, "POST", postData);
            }else
            {
                lstrResponse = this.getWebResponse(outUrl, "GET", string.Empty);
            }
            return lstrResponse;
        }

        public Boolean getRequestToken(ref string aRefstrOauth_token,ref string aRefstrOauth_token_secret)
        {
            try
            {
                Uri uri = new Uri(this.RequestTokenUrl);
                string nonce = m_oOAuth.GenerateNonce();
                string timeStamp = m_oOAuth.GenerateTimeStamp();
                string normalizeUrl, normalizedRequestParameters;

                // 签名
                string sig = m_oOAuth.GenerateSignature(
                    uri,
                    this.m_strConsumerKey,
                    this.m_strConsumerSecret,
                    string.Empty,
                    string.Empty,
                    "GET",
                    timeStamp,
                    nonce,
                    null,
                    OAuthBase.SignatureTypes.HMACSHA1,
                    out normalizeUrl,
                    out normalizedRequestParameters);

                sig = HttpUtility.UrlEncode(sig);

                //构造请求Request Token的url
                StringBuilder sb = new StringBuilder(uri.ToString());
                sb.AppendFormat("?oauth_consumer_key={0}&", this.m_strConsumerKey);
                sb.AppendFormat("oauth_nonce={0}&", nonce);
                sb.AppendFormat("oauth_timestamp={0}&", timeStamp);
                sb.AppendFormat("oauth_signature_method={0}&", "HMAC-SHA1");
                sb.AppendFormat("oauth_version={0}&", "1.0");
                sb.AppendFormat("oauth_signature={0}", sig);

                if (this.m_bShowDebugInfo)
                {
                    Debug.WriteLine("请求Request Token的url: \n" + sb.ToString());
                }

                //请求Request Token
                string responseBody = getWebResponse(sb.ToString(), "GET", string.Empty);

                if (this.m_bShowDebugInfo)
                {
                    Debug.WriteLine("请求Request Token的返回值: \n" + responseBody);
                }

                //解析返回的Request Token和Request Token Secret
                System.Collections.Specialized.NameValueCollection responseValues = HttpUtility.ParseQueryString(responseBody);

                this.m_strOAuthToken = responseValues["oauth_token"];

                this.m_strOAuthTokenSecret = responseValues["oauth_token_secret"];

                if (String.IsNullOrEmpty(this.m_strOAuthToken) || String.IsNullOrEmpty(this.m_strOAuthTokenSecret))
                {
                    return false;
                }

                return true;
            }
            catch (System.Exception ex)
            {
                if (this.m_bShowDebugInfo)
                {
                    Debug.WriteLine(ex.ToString());
                }
                return false;
            }

            
        }

        public Boolean getAuthorize(string astrUserName, string astrPassword, ref string astrOauth_verifier)
        {
            string lstrUrl = this.m_strAuthorizeUrl + "?oauth_token=" + this.m_strOAuthToken + "&oauth_callback=xml&userId=" + astrUserName + "&passwd=" + astrPassword;
          
            string lstrResponseBody = getWebResponse(lstrUrl, "GET", string.Empty);

            if (lstrResponseBody!= null)
            {
                XmlDocument loDoc = new XmlDocument();

                loDoc.LoadXml(lstrResponseBody);

                System.Xml.XmlNodeList  loNodes = loDoc.SelectNodes("//oauth//oauth_verifier");

                System.Xml.XmlNode loNode = loNodes[0];

                this.Verifier = loNode.InnerText;

                if (this.m_bShowDebugInfo)
                {
                    Debug.WriteLine("Verifier:" + this.Verifier);
                }

                if (string.IsNullOrEmpty(this.Verifier))
                {
                    return false;
                }

                return true;
            }
            
            return false;
        }

        public Boolean getAccessToken(string astrOauth_verifier)
        {
            try
            {
                Uri uri = new Uri(this.m_strAccessTokenUrl);
                string nonce = m_oOAuth.GenerateNonce();
                string timeStamp = m_oOAuth.GenerateTimeStamp();
                string normalizeUrl, normalizedRequestParameters; 
                String lstrKey = this.m_strVerifier;
                // 签名
                string sig = m_oOAuth.GenerateSignature(
                    uri,
                    this.m_strConsumerKey,
                    this.m_strConsumerSecret,
                    this.m_strOAuthToken,
                    this.m_strOAuthTokenSecret,
                    "GET",
                    timeStamp,
                    nonce,
                    lstrKey,
                    OAuthBase.SignatureTypes.HMACSHA1,
                    out normalizeUrl,
                    out normalizedRequestParameters);
                sig = HttpUtility.UrlEncode(sig);

                //构造请求Access Token的url

                StringBuilder sb = new StringBuilder(uri.ToString());
                sb.AppendFormat("?oauth_consumer_key={0}&", this.m_strConsumerKey);
                sb.AppendFormat("oauth_nonce={0}&", nonce);
                sb.AppendFormat("oauth_timestamp={0}&", timeStamp);
                sb.AppendFormat("oauth_signature_method={0}&", "HMAC-SHA1");
                sb.AppendFormat("oauth_version={0}&", "1.0");
                sb.AppendFormat("oauth_signature={0}&", sig);
                sb.AppendFormat("oauth_token={0}&", this.m_strOAuthToken);
                sb.AppendFormat("oauth_verifier={0}&", lstrKey);

                if (this.m_bShowDebugInfo)
                {
                    Debug.WriteLine("请求Access Token的url: \n" + sb.ToString());
                }


                string responseBody = this.getWebResponse(sb.ToString(), "GET", string.Empty);

                if (this.m_bShowDebugInfo)
                {
                    Debug.WriteLine("请求Access Token的返回值: \n" + responseBody);
                }

                System.Collections.Specialized.NameValueCollection responseValues = HttpUtility.ParseQueryString(responseBody);
                this.AccessToken = responseValues["oauth_token"];
                this.AccessTokenSecret = responseValues["oauth_token_secret"];


                if (!string.IsNullOrEmpty(this.AccessToken)&& !string.IsNullOrEmpty(this.AccessTokenSecret))
                {
                    return true;
                }
            }
            catch (System.Exception ex)
            {
            	if (this.m_bShowDebugInfo)
            	{
                    Debug.WriteLine(ex.ToString());
            	}
            }

            return false;
        }
  
    }
}
